home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
9-Digit Zip Code Directory
/
9-Digit Zip Code Directory (American Business Information) (ABIZIP-12).ISO
/
z4src.zip
/
Z4PARSE.CPP
< prev
next >
Wrap
C/C++ Source or Header
|
1993-08-22
|
32KB
|
1,220 lines
//----------------------------------------------------------------------------
// MODULE DESCRIPTION
//
// Module: z4parse.cpp
// Title: ZIP+4 Engine
// Notice: John M. Weeder
// Copyright (c) 1993. All rights reserved.
// This module contains proprietary information and should be
// treated as confidential.
//
//----------------------------------------------------------------------------
// MAINTENANCE HISTORY
//
// $Workfile$
// $Revision$
// $Author$
// $Date$
// $Log$
//
//----------------------------------------------------------------------------
// MODULE NARRATIVE
//
// This module contains code for the class Z4_INQ.
//
// The code in this module may be written in C++ or C.
//
// This module is portable to:
// DOS 3.X+
// MS Windows 3.X+
// OS/2 2.X+
// OS/2 2.0 PM
//
// The following compilers are supported:
// MSC 6.0A
// MSC/C++ 7.0
// Borland C++ 3.1 for DOS
// Borland C++ 1.0 for OS/2 2.X
//
//----------------------------------------------------------------------------
#include <z4.h>
//----------------------------------------------------------------------------
// Globals
//----------------------------------------------------------------------------
SIZET Z4_PARSE::cBuf;
CHAR Z4_PARSE::szBuffer[256];
SIZET Z4_PARSE::cStack;
Z4_PARSE_ELEM Z4_PARSE::pelem[MAX_PARSE_ELEM];
//----------------------------------------------------------------------------
// Description: Default constructor
// Parameters:
// Returns:
//----------------------------------------------------------------------------
FN_M Z4_PARSE::Z4_PARSE()
{
Z4_PARSE::Initialize(CL_INIT_CLASS);
}
//----------------------------------------------------------------------------
// Description: Copy constructor
// Parameters: rcz4_parse Reference to object to copy.
// Returns:
//----------------------------------------------------------------------------
FN_M Z4_PARSE::Z4_PARSE(RCZ4_PARSE rcz4_parse)
{
Z4_PARSE::Initialize(CL_INIT_CLASS);
*this = rcz4_parse;
}
//----------------------------------------------------------------------------
// Description: Destructor
// Parameters:
// Returns:
//----------------------------------------------------------------------------
FN_M Z4_PARSE::~Z4_PARSE()
{
Z4_PARSE::Destroy(FALSE);
}
//----------------------------------------------------------------------------
// Description:
// Parameters:
// Returns: TRUE if successful.
//----------------------------------------------------------------------------
VOID FN_M Z4_PARSE::Abbreviate()
{
Z4_AB_FILE ab_file;
//
// Abbreviate words
//
for (SIZET i = 0; i < cStack; ++i)
{
if ((pelem[i].fs & (Z4_P_NUMERIC|Z4_P_EOW)) == Z4_P_NUMERIC
&& (pelem[i+1].fs & (Z4_P_ALPHA|Z4_P_EOW)) == (Z4_P_ALPHA|Z4_P_EOW)
&& pelem[i+1].cLen)
{
PCSZ pcszWord = Word(pelem[i+1].cWord);
if (strcmp(pcszWord, "ST") == 0
|| strcmp(pcszWord, "RD") == 0
|| strcmp(pcszWord, "TH") == 0
|| strcmp(pcszWord, "ND") == 0)
{
pelem[i+1].fs |= Z4_P_ORDINAL;
i++;
continue;
}
}
PCSZ pcszWord = Word(pelem[i].cWord);
BOOL fEOW = (pelem[i].fs & Z4_P_EOW) != 0;
if (ab_file.Find(pcszWord))
{
PCSZ pcszChg = ab_file.Abbreviation();
pelem[i].fs = ab_file.Flags() | (fEOW ? Z4_P_EOW: 0);
if (strcmp(pcszWord, pcszChg) != 0)
{
pelem[i].fs |= Z4_P_CHG;
pelem[i].cWord = AddString(pcszChg);
pelem[i].cLen = strlen(pcszChg);
}
}
}
return ;
}
//----------------------------------------------------------------------------
// Description:
// Parameters:
// Returns: TRUE if successful.
//----------------------------------------------------------------------------
SIZET FN_M Z4_PARSE::AddString(PCCHAR pch, SIZET cch)
{
if (!cch)
cch = strlen(pch);
Assert(sizeof(szBuffer) - cBuf > cch + 1);
SIZET cOffset = cBuf;
memcpy(szBuffer + cBuf, pch, cch);
cBuf += cch;
szBuffer[cBuf] = '\0';
cBuf++;
return cOffset;
}
//----------------------------------------------------------------------------
// Description: Handle specal cases where a single letter follows the word
// 'AVENUE'.
//
// AVENUE N -> AVENUE N
// N E AVENUE N -> NE AVENUE N
// N E AVENUE N W -> NE AVENUE N W
// N E AVENUE N N W -> NE AVENUE N NW
// N E AVENUE N NW -> NE AVENUE N NW
//
// Parameters:
// Returns: TRUE if successful.
//----------------------------------------------------------------------------
VOID FN_M Z4_PARSE::AvenueX()
{
SIZET i = 0, j;
// Predirection
if (i < cStack && BTEST(pelem[i].fs, Z4_P_DIR))
{
PCSZ pcsz1 = Word(pelem[i].cWord);
SIZET cLen = pelem[i].cLen;
i++;
if (cLen == 1
&& (pcsz1[0] == 'N'
|| pcsz1[0] == 'S')
&& i < cStack
&& BTEST(pelem[i].fs, Z4_P_DIR)
&& pelem[i].cLen == 1)
{
PCSZ pcsz2 = Word(pelem[i].cWord);
if (pcsz2[0] == 'W' || pcsz2[0] == 'E')
i++;
}
}
// Avenue X
if (i < cStack
&& BTEST(pelem[i].fs, Z4_P_SUFFIX)
&& strcmp(Word(pelem[i].cWord), "AVE") == 0)
{
j = i;
i++;
if (i < cStack
&& strlen(Word(pelem[i].cFull)) == 1
&& BTEST(pelem[i].fs, Z4_P_EOW))
i++;
else
return ;
}
else
return ;
// Post direction
if (i < cStack && BTEST(pelem[i].fs, Z4_P_DIR))
{
PCSZ pcsz1 = Word(pelem[i].cWord);
SIZET cLen = pelem[i].cLen;
i++;
if (cLen == 1
&& (pcsz1[0] == 'N'
|| pcsz1[0] == 'S')
&& i < cStack
&& BTEST(pelem[i].fs, Z4_P_DIR)
&& pelem[i].cLen == 1)
{
PCSZ pcsz2 = Word(pelem[i].cWord);
if (pcsz2[0] == 'W' || pcsz2[0] == 'E')
i++;
}
}
if (i < cStack) // Not at the end of the address,
return ; // therefore not of correct form
CHAR szWord[20];
sprintf(szWord, "AVENUE %s", Word(pelem[j + 1].cFull));
pelem[j].fs = Z4_P_ALPHA|Z4_P_CHG|Z4_P_EOW;
pelem[j].cWord = AddString(szWord);
pelem[j].cFull = AddString(szWord);
pelem[j].cLen = strlen(szWord);
Delete(j + 1, 1);
return ;
}
//----------------------------------------------------------------------------
// Description:
// Parameters:
// Returns: TRUE if successful.
//----------------------------------------------------------------------------
VOID FN_M Z4_PARSE::Break(PCSZ pcsz)
{
cBuf = 0; // Clear word buffer
cStack = 0; // Clear stack
memset(pelem, 0, sizeof(pelem));
PCHAR pchBegin = (PCHAR)pcsz;
while (pchBegin[0])
{
PCHAR pch = pchBegin;
FLAG16 fs;
if (isascii(pch[0]) && isalpha(pch[0]))
{
pch++; // Alpha
while (isascii(pch[0]) && isalpha(pch[0]))
pch++;
fs = Z4_P_ALPHA;
}
else if (isascii(pch[0]) && isdigit(pch[0]))
{
pch++; // Numeric
while (isascii(pch[0]) && isdigit(pch[0]))
pch++;
fs = Z4_P_NUMERIC;
}
else if (isascii(pch[0]) && isspace(pch[0]))
{
pch++; // Spaces -- skip over them!
while (isascii(pch[0]) && isspace(pch[0]))
pch++;
if (cStack) // Add end of word marker
pelem[cStack - 1].fs |= Z4_P_EOW;
pchBegin = pch; // Don't add anything to stack!
}
else
{
pch++; // Only add on character to stack
fs = Z4_P_OTHER;
}
SIZET cLen = (SIZET)(pch - pchBegin);
if (cLen) // Add phrase to stack
{
SIZET cWord = AddString(pchBegin, cLen);
Assert(cStack < MAX_PARSE_ELEM);
pelem[cStack].fs = fs;
pelem[cStack].cLen = cLen;
pelem[cStack].cWord = cWord;
pelem[cStack].cFull = cWord;
cStack++;
}
pchBegin = pch;
}
if (cStack) // Place end of word marker on last word
pelem[cStack - 1].fs |= Z4_P_EOW;
return ;
}
//----------------------------------------------------------------------------
// Description:
// Parameters:
// Returns: TRUE if successful.
//----------------------------------------------------------------------------
BOOL FN_M Z4_PARSE::City()
{
Combine(szCity, sizeof(szCity));
return TRUE;
}
//----------------------------------------------------------------------------
// Description:
// Parameters:
// Returns: TRUE if successful.
//----------------------------------------------------------------------------
VOID FN_M Z4_PARSE::Clean()
{
for (SIZET i = 0; i < cStack; ++i)
if (pelem[i].fs & Z4_P_OTHER)
{
PCSZ pcszWord = Word(pelem[i].cWord);
if (pcszWord[0] == '.' && !pcszWord[1])
{
if (i
&& !BTEST(pelem[i-1].fs, Z4_P_EOW)
&& BTEST(pelem[i].fs, Z4_P_EOW))
pelem[i-1].fs |= Z4_P_EOW;
Delete(i); // Delete the period!
i--; // Remain at current word!
}
}
return ;
}
//----------------------------------------------------------------------------
// Description:
// Parameters:
// Returns: TRUE if successful.
//----------------------------------------------------------------------------
VOID FN_M Z4_PARSE::Clear()
{
cBuf = 0; // Clear word buffer
cStack = 0; // Clear stack
memset(pelem, 0, sizeof(pelem));
szAddr1[0] = '\0'; // Input areas
szAddr2[0] = '\0';
szLastLine[0] = '\0';
szCity[0] = '\0'; // Last line
state = Z4_ST_INVALID;
fInvState = FALSE;
szZip5[0] = '\0';
szAddon[0] = '\0';
szZip4[0] = '\0';
szPriNo[0] = '\0'; // Address line 2
szPriNoReformat[0] = '\0';
predir = Z4_DIR_BLANK;
szPriName[0] = '\0';
fPriNumeric = FALSE;
suffix1 = 0;
suffix2 = 0;
postdir = Z4_DIR_BLANK;
unit = Z4_UNIT_BLANK;
szSecNo[0] = '\0';
szSecName[0] = '\0'; // Address line 1
return ;
}
//----------------------------------------------------------------------------
// Description:
// Parameters:
// Returns: TRUE if successful.
//----------------------------------------------------------------------------
VOID FN_M Z4_PARSE::Collapse()
{
#define MAX_CWORD (5)
struct Z4_PARSE_COLLAPSE
{
PCSZ pcsz;
FLAG16 fs;
PCSZ apcsz[MAX_CWORD];
};
static Z4_PARSE_COLLAPSE _FAR_ collapse[] =
{
{ "RR", Z4_P_RR|Z4_P_ALPHA, { "R", "RT" }},
{ "RR", Z4_P_RR|Z4_P_ALPHA, { "R", ".", "RT" }},
{ "RR", Z4_P_RR|Z4_P_ALPHA, { "R", "R" }},
{ "RR", Z4_P_RR|Z4_P_ALPHA, { "R", ".", "R", "."}},
{ "RR", Z4_P_RR|Z4_P_ALPHA, { "RURAL", "RR" }},
{ "POB", Z4_P_POB|Z4_P_ALPHA, { "PO", "BOX" }},
{ "PO", Z4_P_ALPHA, { "POST", "OFC" }},
{ "HC", Z4_P_HC|Z4_P_ALPHA, { "HWY", "CONTRACT" }},
{ NULL }
};
for (SIZET i = 0; i < cStack; ++i)
{
for (SHORT j = 0; collapse[j].pcsz; ++j)
{
BOOL fMatch = TRUE;
CHAR szFull[MAX_ADDR+1];
szFull[0] = '\0';
for (SIZET k = 0; k < MAX_CWORD && collapse[j].apcsz[k]; ++k)
{
PCSZ pcszWord = Word(pelem[i+k].cWord);
if (i + k >= cStack
|| strcmp(pcszWord, collapse[j].apcsz[k]) != 0)
{
fMatch = FALSE;
break;
}
strcats(szFull, pcszWord);
}
if (fMatch) // Collapse 2 or more words into one
{
Assert(k > 1);
pelem[i].fs = collapse[j].fs|Z4_P_CHG|Z4_P_EOW;
pelem[i].cWord = AddString(collapse[j].pcsz);
pelem[i].cFull = AddString(szFull);
pelem[i].cLen = strlen(collapse[j].pcsz);
Delete(i + 1, k - 1);
i--; // Restart at current word!
break;
}
}
}
return ;
}
//----------------------------------------------------------------------------
// Description:
// Parameters:
// Returns: TRUE if successful.
//----------------------------------------------------------------------------
PCSZ FN_M Z4_PARSE::Combine(PSZ psz, SIZET cch, SIZET cStart, SIZET cEnd, BOOL fSpace)
{
PSZ pszStart = psz;
cEnd = MIN(cEnd, cStack);
cStart = MIN(cStart, cEnd);
Assert(cch >= 1);
cch--; // Leave room for null terminator
for (SIZET i = cStart; cch && i < cEnd; ++i)
{
PSZ pszWord = Word(pelem[i].cFull);
SIZET cLen = strlen(pszWord);
if (cch < cLen) // If no room for word, break
break;
// Concat word to string
memcpy(psz, pszWord, cLen);
psz += cLen;
cch -= cLen;
// Add space after a word
if (cch && (pelem[i].fs & Z4_P_EOW) && fSpace)
{
*psz++ = ' ';
cch--;
}
}
psz[0] = '\0'; // Null terminator
strtrimright(pszStart); // Remove trailing spaces
return pszStart;
}
//----------------------------------------------------------------------------
// Description:
// Parameters:
// cElem Number of elements to delete
// Default is 1.
// Returns: TRUE if successful.
//----------------------------------------------------------------------------
VOID FN_M Z4_PARSE::Delete(SIZET cDelete, SIZET cElem)
{
Assert(cStack);
Assert(cDelete < cStack);
cElem = MIN(MAX(1, cElem), cStack - cDelete);
SIZET cEnd = cDelete + cElem; // Element at end of delete area
SIZET cMove = cStack - cEnd; // Element to move down
if (cMove)
memcpy(pelem + cDelete, pelem + cEnd, cMove * sizeof(Z4_PARSE_ELEM));
cStack -= cElem;
return ;
}
//----------------------------------------------------------------------------
// Description: Destroy object. Free any resources used by object.
// Normally called by destructor.
// Should allow multiple calls from various classes.
// A class should almost always re-init its variables when
// it is destroyed to prevent accidents.
// Parameters: fDestroyAll Destroy parents also?
// Default is TRUE.
// Returns: TRUE if successful.
//----------------------------------------------------------------------------
BOOL FN_M Z4_PARSE::Destroy(BOOL fDestroyAll)
{
Z4_PARSE::Initialize(CL_INIT_CLASS_VARS);
if (fDestroyAll) // Destroy parent.
Z4_PARSE_PARENT::Destroy(fDestroyAll);
return TRUE;
}
//----------------------------------------------------------------------------
// Description: Initialize object.
// Normally called by constructor.
// Should allow multiple calls from various classes.
// Parameters: sInit Initialization code. May be one of the following:
// CL_INIT_CLASS Reset class variables and
// and dynamic allocations for
// this class only.
// CL_INIT_CLASS_VARS Reset class variables for
// this class only.
// CL_INIT_VARS Reset class variables for
// this class only.
// CL_INIT_ALL Initialize class and all
// parent class, including
// dynamic memory allocation.
// Default is CL_INIT_ALL
// Returns: TRUE if successful.
//----------------------------------------------------------------------------
BOOL FN_M Z4_PARSE::Initialize(SHORT sInit)
{
if (sInit == CL_INIT_VARS || sInit == CL_INIT_ALL)
Z4_PARSE_PARENT::Initialize(sInit);
Clear();
return TRUE;
}
//----------------------------------------------------------------------------
// Description:
// Parameters:
// Returns: TRUE if successful.
//----------------------------------------------------------------------------
BOOL FN_M Z4_PARSE::LastLine(PCSZ pcszZip, PCSZ pcszCity, PCSZ pcszState)
{
if (!pcszCity)
pcszCity = "";
if (!pcszState)
pcszState = "";
if (!pcszZip)
pcszZip = "";
//
// Build the complete last line
//
strnzcpy(szLastLine, pcszCity, sizeof(szLastLine));
if (strlen(szLastLine) + strlen(pcszState) + 1 < sizeof(szLastLine))
strcats(szLastLine, pcszState);
if (strlen(szLastLine) + strlen(pcszZip) + 1 < sizeof(szLastLine))
strcats(szLastLine, pcszZip);
strupr(szLastLine);
//
// Parse the last line
//
Break(szLastLine);
Clean();
Zip4();
State();
City();
return TRUE;
}
//----------------------------------------------------------------------------
// Description:
// Parameters:
// Returns: TRUE if successful.
//----------------------------------------------------------------------------
VOID FN_M Z4_PARSE::Ordinal()
{
//
// Delete any ordinals which follow numerics. IE 10TH --> 10
//
for (SIZET i = 0; i + 1 < cStack; ++i)
{
if ((pelem[i].fs & (Z4_P_NUMERIC|Z4_P_EOW)) == Z4_P_NUMERIC
&& (pelem[i+1].fs & (Z4_P_ALPHA|Z4_P_EOW)) == (Z4_P_ALPHA|Z4_P_EOW)
&& pelem[i+1].cLen)
{
PCSZ pcszWord = Word(pelem[i+1].cWord);
if (strcmp(pcszWord, "ST") == 0
|| strcmp(pcszWord, "RD") == 0
|| strcmp(pcszWord, "TH") == 0
|| strcmp(pcszWord, "ND") == 0)
{
Delete(i + 1, 1);
pelem[i].fs |= Z4_P_EOW|Z4_P_ORDINAL;
}
}
}
return ;
}
//----------------------------------------------------------------------------
// Description:
// Parameters:
// Returns: TRUE if successful.
//----------------------------------------------------------------------------
BOOL FN_M Z4_PARSE::POB()
{
if (pelem[0].fs & Z4_P_POB)
{
szSecNo[0] = '\0'; // No secondary number
strcpy(szPriName, "PO BOX");
Combine(szPriNo, sizeof(szPriNo), 1);
strcpy(szPriNoReformat, szPriNo);
return TRUE;
}
return FALSE;
}
//----------------------------------------------------------------------------
// Description:
// Parameters:
// Returns: TRUE if successful.
//----------------------------------------------------------------------------
VOID FN_M Z4_PARSE::PostDir()
{
if (cStack > 2
&& (pelem[cStack - 1].fs & Z4_P_DIR)
&& (pelem[cStack - 2].fs & Z4_P_DIR))
{
PCSZ pcsz1 = Word(pelem[cStack - 2].cWord);
PCSZ pcsz2 = Word(pelem[cStack - 1].cWord);
if (pcsz1[0] == 'N')
{
if (pcsz2[0] == 'E')
postdir = Z4_DIR_NE;
else if (pcsz2[0] == 'W')
postdir = Z4_DIR_NW;
}
else if (pcsz1[0] == 'S')
{
if (pcsz2[0] == 'E')
postdir = Z4_DIR_SE;
else if (pcsz2[0] == 'W')
postdir = Z4_DIR_SW;
}
if (postdir != Z4_DIR_BLANK)
Delete(cStack - 2, 2);
}
if (cStack > 1
&& (pelem[cStack - 1].fs & Z4_P_DIR))
{
PCSZ pcsz = Word(pelem[cStack - 1].cWord);
switch (pcsz[0])
{
case 'N':
if (pcsz[1] == 'W')
postdir = Z4_DIR_NW;
else if (pcsz[1] == 'E')
postdir = Z4_DIR_NE;
else
postdir = Z4_DIR_N;
break;
case 'S':
if (pcsz[1] == 'W')
postdir = Z4_DIR_SW;
else if (pcsz[1] == 'E')
postdir = Z4_DIR_SE;
else
postdir = Z4_DIR_S;
break;
case 'E':
postdir = Z4_DIR_E;
break;
case 'W':
postdir = Z4_DIR_W;
break;
default:
return ;
}
Delete(cStack - 1, 1);
}
return ;
}
//----------------------------------------------------------------------------
// Description:
// Parameters:
// Returns: TRUE if successful.
//----------------------------------------------------------------------------
VOID FN_M Z4_PARSE::PreDir()
{
if (cStack > 2
&& (pelem[0].fs & Z4_P_DIR)
&& (pelem[1].fs & Z4_P_DIR))
{
PCSZ pcsz1 = Word(pelem[0].cWord);
PCSZ pcsz2 = Word(pelem[1].cWord);
if (pcsz1[0] == 'N')
{
if (pcsz2[0] == 'E')
predir = Z4_DIR_NE;
else if (pcsz2[0] == 'W')
predir = Z4_DIR_NW;
}
else if (pcsz1[0] == 'S')
{
if (pcsz2[0] == 'E')
predir = Z4_DIR_SE;
else if (pcsz2[0] == 'W')
predir = Z4_DIR_SW;
}
if (predir != Z4_DIR_BLANK)
Delete(0, 2);
}
if (cStack > 1
&& (pelem[0].fs & Z4_P_DIR))
{
PCSZ pcsz = Word(pelem[0].cWord);
switch (pcsz[0])
{
case 'N':
if (pcsz[1] == 'W')
predir = Z4_DIR_NW;
else if (pcsz[1] == 'E')
predir = Z4_DIR_NE;
else
predir = Z4_DIR_N;
break;
case 'S':
if (pcsz[1] == 'W')
predir = Z4_DIR_SW;
else if (pcsz[1] == 'E')
predir = Z4_DIR_SE;
else
predir = Z4_DIR_S;
break;
case 'E':
predir = Z4_DIR_E;
break;
case 'W':
predir = Z4_DIR_W;
break;
default:
return ;
}
Delete(0,1);
}
return ;
}
//----------------------------------------------------------------------------
// Description:
// Parameters:
// Returns: TRUE if successful.
//----------------------------------------------------------------------------
BOOL FN_M Z4_PARSE::Primary(PCSZ pcszAddr2)
{
Assert(pcszAddr2);
strnzcpy(szAddr2, pcszAddr2, sizeof(szAddr2));
strupr(szAddr2);
Break(szAddr2);
Abbreviate();
AvenueX();
Collapse();
SecNo();
if (RRHC())
return TRUE;
if (POB())
return TRUE;
PriNo();
Ordinal();
Clean();
Collapse();
PostDir();
suffix1 = Suffix();
suffix2 = Suffix();
if (suffix2 == 0)
{
suffix2 = suffix1;
suffix1 = 0;
}
PreDir();
PriName();
if (strlen(szSecNo) > MAX_SEC_NO)
szSecNo[MAX_SEC_NO] = '\0';
if (strlen(szPriNo) > MAX_PRI_NO)
szPriNo[MAX_PRI_NO] = '\0';
if (strlen(szPriNoReformat) > MAX_PRI_NO)
szPriNoReformat[MAX_PRI_NO] = '\0';
return TRUE;
}
//----------------------------------------------------------------------------
// Description:
// Parameters:
// Returns: TRUE if successful.
//----------------------------------------------------------------------------
VOID FN_M Z4_PARSE::PriName()
{
if (cStack == 1 && (pelem[0].fs & Z4_P_NUMERIC))
strcpy(szPriName,Word(pelem[0].cWord));
else
Combine(szPriName, sizeof(szPriName));
fPriNumeric = TRUE;
for (SIZET i = 0; szPriName[i]; ++i)
if (!isdigit(szPriName[i]))
fPriNumeric = FALSE;
return ;
}
//----------------------------------------------------------------------------
// Description:
// Parameters:
// Returns: TRUE if successful.
//----------------------------------------------------------------------------
VOID FN_M Z4_PARSE::PriNo()
{
Range(szPriNo, sizeof(szPriNo), 0, Z4_P_PRINO);
strcpy(szPriNoReformat, szPriNo);
return ;
}
//----------------------------------------------------------------------------
// Description:
// Parameters:
// Returns: TRUE if successful.
//----------------------------------------------------------------------------
BOOL FN_M Z4_PARSE::Range(PSZ psz, SIZET cch, SIZET cStart, FLAG16 fs)
{
SIZET cTotal = 0; // Size of number
BOOL fDigit = FALSE; // Last digit numeric?
BOOL fNumeric = FALSE; // Numeric characters found?
BOOL fPrimary = BTEST(fs, Z4_P_PRINO);
//
// Do not extract single word secondary ranges if they
// are also a directional or suffix word.
// Ignore this rule if
// EX: BAY MEADOWS TRAILER CT
//
if (!fPrimary
&& BTEST(pelem[cStart].fs, Z4_P_EOW)
&& BTEST(pelem[cStart].fs, Z4_P_SUFFIX|Z4_P_DIR)
&& !BTEST(fs, Z4_P_SECNO_FORCE))
return FALSE;
//
// Do not extract primary ranges the word is an ordinal number.
// This parses 13TH ST as having no range.
//
//
if (fPrimary
&& (pelem[cStart].fs & Z4_P_NUMERIC)
&& (pelem[cStart+1].fs & Z4_P_ORDINAL))
return FALSE;
for (SIZET i = cStart; i < cStack; ++i)
{
PCSZ pcsz = Word(pelem[i].cWord);
if (pelem[i].fs & Z4_P_NUMERIC) // Word is numeric
{
cTotal += pelem[i].cLen;
fDigit = TRUE;
fNumeric = TRUE;
} // Word is alpha
else if (pelem[i].fs & Z4_P_ALPHA)
{
cTotal += pelem[i].cLen;
fDigit = FALSE;
} // Either a dash or period
else if ((pelem[i].fs & Z4_P_OTHER)
&& pelem[i].cLen == 1
&& (pcsz[0] == '-' || pcsz[0] == '.'))
{
cTotal++;
fDigit = FALSE;
}
else
break;
if (pelem[i].fs & Z4_P_EOW) // End of word, break
{
i++;
break;
}
}
if (i == cStart) // Nothing found!
return FALSE;
if (!fNumeric && fPrimary) // No numeric found, so exit
return FALSE;
SIZET cFract = i, cFractTotal = 0;
if (cFract < cStack) // Single numeric (as in 1 / 2)
{
if ((pelem[cFract].fs & Z4_P_NUMERIC)
&& pelem[cFract].cLen == 1)
{
fDigit = TRUE;
cFractTotal++;
cFract++;
}
}
if (fDigit // First character of fraction found,
&& cFract < cStack // look for remainder
&& (pelem[cFract].fs & Z4_P_OTHER)
&& pelem[cFract].cLen == 1)
{
PCSZ pcsz = Word(pelem[cFract].cWord);
if (pcsz[0] == '/') // Look for denominator
{
cFract++;
cFractTotal++;
if (cFract < cStack
&& (pelem[cFract].fs & Z4_P_NUMERIC)
&& pelem[cFract].cLen == 1)
{
cFractTotal++;
i = cFract + 1;
}
}
}
if (cTotal + cFractTotal >= cch) // Invalid number, too long
return FALSE;
if (i >= cStack && cStart == 0) // Don't extract primary number if nothing
return FALSE; // would remain
// Extract and remove from stack
Combine(psz, cch, cStart, i, FALSE);
Delete(cStart, i - cStart);
return TRUE;
}
//----------------------------------------------------------------------------
// Description:
// Parameters:
// Returns: TRUE if successful.
//----------------------------------------------------------------------------
BOOL FN_M Z4_PARSE::RRHC()
{
if (pelem[0].fs & (Z4_P_RR|Z4_P_HC))
{
strcpy(szPriNo, szSecNo); // Move secondary number, if any, to the
szSecNo[0] = '\0'; // primary number
strcpy(szPriNoReformat, szPriNo);
if (pelem[0].fs & Z4_P_RR)
strcpy(szPriName, "RR ");
else
strcpy(szPriName, "HC ");
Combine(strchr(szPriName, '\0'), sizeof(szPriName), 1);
return TRUE;
}
return FALSE;
}
//----------------------------------------------------------------------------
// Description:
// Parameters:
// Returns: TRUE if successful.
//----------------------------------------------------------------------------
BOOL FN_M Z4_PARSE::Secondary(PCSZ pcszAddr1)
{
Assert(pcszAddr1);
strnzcpy(szAddr1, pcszAddr1, sizeof(szAddr1));
Z4Clean(szAddr1);
//
// Temporary address line 1 parse. Does not look for
// anything special like secondary ranges.
//
strnzcpy(szSecName, szAddr1, sizeof(szSecName));
return TRUE;
}
//----------------------------------------------------------------------------
// Description:
// Parameters:
// Returns: TRUE if successful.
//----------------------------------------------------------------------------
VOID FN_M Z4_PARSE::SecNo()
{
if (cStack <= 1)
return ;
//
// Look for a normal unit designator, followed by a secondary number
//
if (cStack <= 1)
return ;
for (SIZET i = cStack - 2; i > 1; --i)
if (pelem[i].fs & Z4_P_UNIT)
{
FLAG16 fs = Z4_P_SECNO;
if (pelem[i].cLen == 1) // '#'
fs |= Z4_P_SECNO_FORCE;
if (Range(szSecNo, sizeof(szSecNo), i + 1, fs))
{
PCSZ pcsz = Word(pelem[i].cWord);
unit = Z4FindUnit(pcsz);
if (unit != Z4_UNIT_BLANK)
{
Delete(i, 1);
return ;
}
szSecNo[0] = '\0'; // This should not happen!!!
}
}
//
// Normal unit designator not found, look for an exceptional
// unit designator
//
for (i = 1; i < cStack; ++i)
if (pelem[i].fs & Z4_P_EXCEPT)
{
PCSZ pcsz = Word(pelem[i].cWord);
unit = Z4FindUnit(pcsz);
if (unit != Z4_UNIT_BLANK)
{
strcpy(szSecNo, pcsz);
Delete(i, 1);
return ;
}
}
return ;
}
//----------------------------------------------------------------------------
// Description:
// Parameters:
// Returns: TRUE if successful.
//----------------------------------------------------------------------------
BOOL FN_M Z4_PARSE::State()
{
while (cStack && BTEST(pelem[cStack - 1].fs, (Z4_P_NUMERIC|Z4_P_OTHER)))
Delete(cStack - 1, 1);
//
// Be careful of states such as Virginia vs West Virginia. Don't just
// extract the first word at the end of the line.
//
// First attempt is to pull a 2 digit state code off the end of the
// word.
//
if (cStack >= 1
&& (pelem[cStack - 1].fs & Z4_P_ALPHA)
&& pelem[cStack - 1].cLen == MAX_STATE)
{
CHAR szState[MAX_STATE+1];
strcpy(szState, Word(pelem[cStack - 1].cWord));
state = Z4_INQ::st_file.Find(szState);
if (state == Z4_ST_INVALID)
fInvState = TRUE;
Delete(cStack - 1, 1);
}
else if (cStack >= 1)
{
CHAR szState[MAX_ADDR_LINE+1];
for (SIZET i = 0; i < cStack; ++i)
{
Combine(szState, sizeof(szState), i);
state = Z4_INQ::st_file.Find(szState);
if (state != Z4_ST_INVALID)
{
Delete(i, 0xFFFF);
return TRUE;
}
}
}
return TRUE;
}
//----------------------------------------------------------------------------
// Description:
// Parameters:
// Returns: TRUE if successful.
//----------------------------------------------------------------------------
Z4_SUFFIX FN_M Z4_PARSE::Suffix()
{
Z4_SUFFIX suffix = 0;
//
// This logic is an attempt to deal with ambiguous addresses.
// Rules:
// 1) If 2 words remain in the primary name and the first is a
// directional and the second is a suffix, only remove the
// suffix if it is a valid abbreviation
//
// Example:
// Pre Primary Suffix
// W CENTER --> W CENTER
// W CTR --> W CTR
//
//
if (cStack == 2
&& BTEST(pelem[0].fs, Z4_P_DIR)
&& BTEST(pelem[1].fs, Z4_P_SUFFIX))
{
Z4SuffixFindAbbrev(Word(pelem[1].cWord), &suffix);
PCSZ pcszFull = Z4SuffixFull(suffix);
if (strcmp(pcszFull, Word(pelem[1].cFull)) == 0)
return 0;
}
//
// Remove a suffix from the end of an address
//
if (cStack > 1
&& (pelem[cStack - 1].fs & Z4_P_SUFFIX))
{
if (Z4SuffixFindAbbrev(Word(pelem[cStack - 1].cWord), &suffix))
Delete(cStack - 1, 1);
}
return suffix;
}
//----------------------------------------------------------------------------
// Description:
// Parameters:
// Returns: TRUE if successful.
//----------------------------------------------------------------------------
BOOL FN_M Z4_PARSE::Zip4()
{
if (cStack >= 3
&& (pelem[cStack - 3].fs & Z4_P_NUMERIC)
&& pelem[cStack - 3].cLen == MAX_ZIP5
&& (pelem[cStack - 2].fs & Z4_P_OTHER)
&& pelem[cStack - 2].cLen == 1
&& strcmp(Word(pelem[cStack - 2].cWord) , "-") == 0
&& (pelem[cStack - 1].fs & Z4_P_NUMERIC)
&& pelem[cStack - 1].cLen == MAX_ADDON)
{
strcpy(szZip5, Word(pelem[cStack - 3].cWord));
strcpy(szAddon, Word(pelem[cStack - 1].cWord));
Delete(cStack - 3, 3);
}
else if (cStack >= 1
&& (pelem[cStack - 1].fs & Z4_P_NUMERIC)
&& pelem[cStack - 1].cLen == MAX_ZIP5)
{
strcpy(szZip5, Word(pelem[cStack - 1].cWord));
szAddon[0] = '\0';
Delete(cStack - 1, 1);
}
else if (cStack >= 1
&& (pelem[cStack - 1].fs & Z4_P_NUMERIC)
&& pelem[cStack - 1].cLen == MAX_ZIP4)
{
strcpy(szZip4, Word(pelem[cStack - 1].cWord));
memcpy(szZip5, szZip4, MAX_ZIP5);
szZip5[MAX_ZIP5] = '\0';
strcpy(szAddon, szZip4 + MAX_ZIP5);
Delete(cStack - 1, 1);
}
if (szZip5[0] && szAddon[0])
{
strcpy(szZip4, szZip5);
strcat(szZip4, szAddon);
}
return TRUE;
}
//----------------------------------------------------------------------------
//------------------------------- End of File --------------------------------
//----------------------------------------------------------------------------